// -----------------------------
// Author: 		Dhaenens Gert	
// Creation: 	12/30/2014 2:09:37 PM				
// -----------------------------

#include "Filters.h"

#include "Noise1234.h"

Float* Filters::Blur(UInt32 uWidth, UInt32 uHeight, UInt32 uChannels, UInt32 uSamples, Float* lpData)
{
	Float* lpOutputData = new Float[uWidth * uHeight * uChannels];
	memset(lpOutputData, 0, uWidth * uHeight * uChannels * sizeof(Float));

	Float* lpAvgData = new Float[uChannels];
	memset(lpAvgData, 0, uChannels * sizeof(Float));

	for (UInt32 y = 0; y < uHeight; ++y)
	{
		for (UInt32 x = 0; x < uWidth; ++x)
		{
			UInt32 idx = (y * uWidth) + x;
			idx *= uChannels;

			UInt32 sampleCount = 0;
			memset(lpAvgData, 0, uChannels * sizeof(Float));

			for (Int32 dy = -((Int32)uSamples); dy < (Int32)uSamples; ++dy)
			{
				if ((Int32)y + dy < 0)
					continue;
				if (y + dy >= uHeight)
					continue;

				for (Int32 dx = -((Int32)uSamples); dx < (Int32)uSamples * 2; ++dx)
				{
					if ((Int32)x + dx < 0)
						continue;
					if (x + dx >= uWidth)
						continue;

					UInt32 nidx = ((y + dy) * uWidth) + (x + dx);
					nidx *= uChannels;

					for (UInt32 c = 0; c < uChannels; ++c)
						lpAvgData[c] += lpData[nidx + c];

					++sampleCount;
				}
			}

			if (sampleCount < 1)
				continue;

			for (UInt32 i = 0; i < uChannels; ++i)
				lpOutputData[idx + i] = lpAvgData[i] / sampleCount;
		}
	}

	delete[] lpAvgData;
	delete[] lpData;
	return lpOutputData;
}
Float* Filters::Normalize(UInt32 uDimensions, Float* lpData)
{
	Float minValue = numeric_limits<Float>::max();
	Float maxValue = numeric_limits<Float>::min();
	for (UInt32 i = 0; i < uDimensions; ++i)
	{
		if (lpData[i] > maxValue)
			maxValue = lpData[i];
		if (lpData[i] < minValue)
			minValue = lpData[i];
	}
	for (UInt32 i = 0; i < uDimensions; ++i)
		lpData[i] = (lpData[i] - minValue) / (maxValue - minValue);

	return lpData;
}
Float* Filters::NoiseVariateMultiply(UInt32 uWidth, UInt32 uHeight, UInt32 uChannels, Bool bIgnoreLastChannel, Float minValue, Float maxValue, Float scale, Float* lpData)
{
	Float* lpOutputData = new Float[uWidth * uHeight * uChannels];
	memcpy_s(lpOutputData, uWidth * uHeight * uChannels * sizeof(Float), lpData, uWidth * uHeight * uChannels * sizeof(Float));

	for (UInt32 y = 0; y < uHeight; ++y)
	{
		for (UInt32 x = 0; x < uWidth; ++x)
		{
			UInt32 idx = (y * uWidth) + x;
			idx *= uChannels;

			Float finalValue = 0.0f;
			UInt32 samples = 8;
			for (UInt32 i = 0; i < samples; ++i)
			{
				Float px = (Float)x / uWidth * (scale * i);
				Float py = (Float)y / uHeight * (scale * i);
				Float val = Noise1234::octave_pnoise(8, 0.05f, px, py, uWidth, uHeight);
				val = (val + 1.0f) / 2.0f;
				finalValue += val;
			}
			finalValue /= samples;

			Float a = Math::Lerp(minValue, maxValue, finalValue);

			for (UInt32 i = 0; i < uChannels; ++i)
			{
				if (i == uChannels - 1 && bIgnoreLastChannel)
					lpOutputData[idx + i] = lpData[idx + i];
				else
					lpOutputData[idx + i] = lpData[idx + i] * a;
			}

		}
	}

	delete[] lpData;
	return lpOutputData;
}
Float* Filters::NoiseVariateAdd(UInt32 uWidth, UInt32 uHeight, UInt32 uChannels, Bool bIgnoreLastChannel, Float minValue, Float maxValue, Float scale, Float* lpData)
{
	Float* lpOutputData = new Float[uWidth * uHeight * uChannels];
	memcpy_s(lpOutputData, uWidth * uHeight * uChannels * sizeof(Float), lpData, uWidth * uHeight * uChannels * sizeof(Float));

	for (UInt32 y = 0; y < uHeight; ++y)
	{
		for (UInt32 x = 0; x < uWidth; ++x)
		{
			UInt32 idx = (y * uWidth) + x;
			idx *= uChannels;

			Float px = (Float)x / uWidth * scale;
			Float py = (Float)y / uHeight * scale;
			Float val = Noise1234::octave_pnoise(8, 0.05f, px, py, uWidth, uHeight);
			val = (val + 1.0f) / 2.0f;

			Float a = Math::Lerp(minValue, maxValue, val);

			for (UInt32 i = 0; i < uChannels; ++i)
			{
				if (i == uChannels - 1 && bIgnoreLastChannel)
					lpOutputData[idx + i] = lpData[idx + i];
				else
					lpOutputData[idx + i] = lpData[idx + i] + a;
			}

		}
	}

	delete[] lpData;
	return lpOutputData;
}
Float* Filters::NoiseVariateAddPerChannel(UInt32 uWidth, UInt32 uHeight, UInt32 uChannels, Bool bIgnoreLastChannel, Float minValue, Float maxValue, Float scale, Float* lpData)
{
	Float* lpOutputData = new Float[uWidth * uHeight * uChannels];
	memcpy_s(lpOutputData, uWidth * uHeight * uChannels * sizeof(Float), lpData, uWidth * uHeight * uChannels * sizeof(Float));

	for (UInt32 i = 0; i < uChannels; ++i)
	{
		if (i == uChannels - 1 && bIgnoreLastChannel)
			continue;

		for (UInt32 y = 0; y < uHeight; ++y)
		{
			for (UInt32 x = 0; x < uWidth; ++x)
			{
				UInt32 idx = (y * uWidth) + x;
				idx *= uChannels;

				Float px = (Float)x / uWidth * scale;
				Float py = (Float)y / uHeight * scale;
				Float val = Noise1234::octave_pnoise(8, 0.05f, px, py, uWidth, uHeight);
				val = (val + 1.0f) / 2.0f;

				Float a = Math::Lerp(minValue, maxValue, val);
				lpOutputData[idx + i] = lpData[idx + i] + a;

			}
		}
	}

	delete[] lpData;
	return lpOutputData;
}
